#include "ItemStack.h"
#include "Item.h"
#include "Game.h"
#include "Constants.h"

char ItemStack::filterChars[NUM_FILTER_TYPES] = {'/', '}', '\\', ']', '.', '[', '!', '?', '+', '\'', '%'};
std::map<GenericType, FilterType> ItemStack::filterMap;
std::map<GenericType, TypeHierarchy> ItemStack::typeHierarchyMap;

ItemStack::ItemStack(std::list<Item*>* items, std::string title, int height) {
	m_title = title;
	m_filter = -1;
	m_currentItem = 0;
	m_height = height;
	m_items = new std::vector<ItemStackItem*>();
	for(std::list<Item*>::iterator iter = items->begin(); iter != items->end(); iter++) {
		ItemStackItem* i = new ItemStackItem();
		i->item = *iter;
		i->selected = false;
		i->visible = true;
		i->filtered = false;
		i->stackChange = 0;
		m_items->push_back(i);
	}
}

ItemStack::~ItemStack() {
	for(std::vector<ItemStackItem*>::iterator iter = m_items->begin(); iter != m_items->end(); iter++) {
		delete *iter;
	}
	m_items->clear();
	delete m_items;
}

void ItemStack::initGameData() {
	filterMap[GT_IT_MELEE_WEAPON] = FT_MELEE_WEAPON;
	filterMap[GT_IT_RANGED_WEAPON] = FT_RANGED_WEAPON;
	filterMap[GT_IT_TOOL] = FT_TOOL;
	filterMap[GT_IT_POTION] = FT_POTION;
	filterMap[GT_IT_SCROLL] = FT_SCROLL;
	filterMap[GT_IT_INGREDIENT] = FT_INGREDIENT;
	filterMap[GT_IT_MISC] = FT_MISC;
	filterMap[GT_IT_FOOD] = FT_FOOD;
	filterMap[GT_IT_SHIELD] = FT_SHIELD;
	filterMap[GT_IT_ARMOR] = FT_ARMOR;
	filterMap[GT_IT_AMMO] = FT_AMMO;
	typeHierarchyMap[GT_IT_MELEE_WEAPON] = TH_MELEE_WEAPON_TYPE;
	typeHierarchyMap[GT_IT_RANGED_WEAPON] = TH_RANGED_WEAPON_TYPE;
	typeHierarchyMap[GT_IT_TOOL] = TH_TOOL_TYPE;
	typeHierarchyMap[GT_IT_POTION] = TH_POTION_TYPE;
	typeHierarchyMap[GT_IT_SCROLL] = TH_SCROLL_TYPE;
	typeHierarchyMap[GT_IT_INGREDIENT] = TH_INGREDIENT_TYPE;
	typeHierarchyMap[GT_IT_MISC] = TH_MISC_TYPE;
	typeHierarchyMap[GT_IT_FOOD] = TH_FOOD_TYPE;
	typeHierarchyMap[GT_IT_SHIELD] = TH_SHIELD_TYPE;
	typeHierarchyMap[GT_IT_ARMOR] = TH_ARMOR_TYPE;
	typeHierarchyMap[GT_IT_AMMO] = TH_AMMO_TYPE;
}

Item* ItemStack::getItem(int mod) const {
	if((mod = convertMod(mod)) == -1) return NULL;
	return m_items->at(mod)->item;
}

void ItemStack::shift(bool up) {
	if(up) {
		m_currentItem = std::max(int(m_currentItem-1), 0);
	} else {
		m_currentItem = std::max(0, std::min(int(m_currentItem+1), getMaxLastIndex()));
	}
}

void ItemStack::page(bool up) {
	if(up) {
		m_currentItem = std::max(int(m_currentItem-getNumDrawableItems()), 0);
	} else {
		m_currentItem = std::max(0, std::min(int(m_currentItem+getNumDrawableItems()), getMaxLastIndex()));
	}
}

int ItemStack::getMaxLastIndex() const {
	int prevTitle = -1, lineNum = -1, index = m_items->size();
	int maxLines = (m_height-g_options.o_fontSize) / (TILE_HEIGHT+4) - 1;
	for(std::vector<ItemStackItem*>::reverse_iterator iter = m_items->rbegin(); iter != m_items->rend() && lineNum != maxLines; iter++) {
		if(!(*iter)->filtered && (*iter)->visible && (*iter)->item->getNumStacked() - (*iter)->stackChange > 0) {
			if(prevTitle != (*iter)->item->getType(TH_GENERIC_TYPE)) {
				lineNum++;
				prevTitle = (*iter)->item->getType(TH_GENERIC_TYPE);
				if(lineNum == maxLines)
					break;
			}
			lineNum++;
		}
		index--;
	}
	for(int i = index-1; i >= 0; i--) {
		if(m_items->at(i)->filtered || !m_items->at(i)->visible || m_items->at(i)->item->getNumStacked() - m_items->at(i)->stackChange <= 0) {
			index--;
		}
	}
	return index;
}

int ItemStack::getNumDrawableItems() const {
	int numDrawable = 0, prevTitle = -1, lineNum = -1;
	int maxLines = (m_height-g_options.o_fontSize) / (TILE_HEIGHT+4) - 1;
	for(unsigned int i = convertMod(0, false); i < m_items->size() && lineNum != maxLines; i++) {
		if(!m_items->at(i)->filtered && m_items->at(i)->visible && m_items->at(i)->item->getNumStacked() - m_items->at(i)->stackChange > 0) {
			if(prevTitle != m_items->at(i)->item->getType(TH_GENERIC_TYPE)) {
				lineNum++;
				prevTitle = m_items->at(i)->item->getType(TH_GENERIC_TYPE);
			}
			if(lineNum != maxLines) {
				lineNum++;
				numDrawable++;
			}
		}
	}
	return numDrawable;
}

int ItemStack::convertMod(int mod, bool checkBounds) const {
	if(checkBounds)
		if(mod < 0 || size_t(mod) >= m_items->size() || mod >= getNumDrawableItems()) return -1;
	int count = -1;
	bool start = false;
	unsigned int i = 0;
	for(; i < m_items->size() && count != mod; i++) {
		if(!m_items->at(i)->filtered && m_items->at(i)->visible && m_items->at(i)->item->getNumStacked() - m_items->at(i)->stackChange > 0) {
			if(!start) {
				start = true;
				i += m_currentItem-1;
			} else {
				count++;
			}
		}
	}
	if(count == mod)
		return i-1;
	return -1;
}

void ItemStack::selectItem(int mod) {
	if((mod = convertMod(mod)) == -1) return;
	m_items->at(mod)->selected = !m_items->at(mod)->selected;
}

std::vector<Item*>* ItemStack::getSelectedItems() const {
	std::vector<Item*>* items = new std::vector<Item*>();
	for(std::vector<ItemStackItem*>::const_iterator iter = m_items->begin(); iter != m_items->end(); iter++) {
		if((*iter)->selected)
			items->push_back((*iter)->item);
	}
	return items;
}

void ItemStack::showOnly(TypeHierarchy typeCategory, int type) {
	for(std::vector<ItemStackItem*>::iterator iter = m_items->begin(); iter != m_items->end(); iter++) {
		(*iter)->visible = (*iter)->item->getType(typeCategory) == type;
	}
	m_currentItem = 0;
}

void ItemStack::show(TypeHierarchy typeCategory, int type) {
	for(std::vector<ItemStackItem*>::iterator iter = m_items->begin(); iter != m_items->end(); iter++) {
		if((*iter)->item->getType(typeCategory) == type)
			(*iter)->visible = true;
	}
	m_currentItem = 0;
}


void ItemStack::setFilter(int filter, bool force) {
	if(m_filter != filter) {
		m_filter = filter;
		for(std::vector<ItemStackItem*>::iterator iter = m_items->begin(); iter != m_items->end(); iter++) {
			(*iter)->filtered = filter == -1 ? false : filterMap[GenericType((*iter)->item->getType(TH_GENERIC_TYPE))] != filter;
		}
		m_currentItem = 0;
	}		
}

void ItemStack::setVisible(Item* item, bool visible) {
	for(std::vector<ItemStackItem*>::iterator iter = m_items->begin(); iter != m_items->end(); iter++) {
		if((*iter)->item == item) {
			(*iter)->visible = visible;
			break;
		}
	}
}

void ItemStack::stackChange(Item* item, int i) {
	for(std::vector<ItemStackItem*>::iterator iter = m_items->begin(); iter != m_items->end(); iter++) {
		if((*iter)->item == item) {
			(*iter)->stackChange += i;
			break;
		}
	}
}
